package com.fand.template.support;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.UUID;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.log4j.Log4j;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

/**
 * FreeMarkerTemplate支持
 * 
 * @author yaoHT
 */
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Log4j
public class TemplateFreeMarkerSupport implements TemplateSupport {
	/**
	 * freemarker.template.Configuratio
	 */
	private Configuration configuration;

	/**
	 * 模板二级缓存
	 */
	private TemplateSupportCache templateSupportCache;

	/**
	 * 文件名解析格式
	 */
	private String filePathFormate = TemplateSupport.DEFAULT_FILE_PATH_FORMATE;

	/**
	 * 文件名变量名称
	 */
	private String filePathVariableName = TemplateSupport.DEFAULT_FILE_PATH_VARIABLE_NAME;

	private Boolean showModel;

	private Boolean showProcessTemplateIntoString;

	private Boolean showTemplateString;

	@Override
	public String processString(final String templateString, final Object model) {
		StringWriter writer = null;

		Reader reader = null;

		try {
			writer = new StringWriter();

			final String name = UUID.randomUUID().toString();

			reader = new StringReader(templateString);

			final Template template = new Template(name, reader, this.configuration);

			template.process(model, writer);

			return writer.toString();
		} catch (final Exception e) {
			throw new RuntimeException(e);
		} finally {
			IOUtils.closeQuietly(reader);

			IOUtils.closeQuietly(writer);
		}
	}

	@Override
	public String processTemplateIntoString(final String filePath, final boolean isFormatFilePath, final Object model) {
		Validate.notEmpty(filePath);

		String str = null;

		if (this.templateSupportCache != null) {
			str = this.templateSupportCache.getTemplateString(filePath);

			if (StringUtils.isNotBlank(str)) {
				return str;
			}
		}

		String newFilePath = null;

		if (isFormatFilePath) {
			newFilePath = StringUtils.replace(this.filePathFormate, this.filePathVariableName, filePath);
		} else {
			newFilePath = filePath;
		}

		Template template;

		try {
			if (BooleanUtils.isTrue(this.showModel)) {
				TemplateFreeMarkerSupport.log.info(ObjectUtils.toString(model));
			}

			template = this.configuration.getTemplate(newFilePath);

			if (BooleanUtils.isTrue(this.showTemplateString)) {
				TemplateFreeMarkerSupport.log.info(template.toString());
			}

			str = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);

			if (BooleanUtils.isTrue(this.showProcessTemplateIntoString)) {
				TemplateFreeMarkerSupport.log.info(str);
			}

			if (this.templateSupportCache != null) {
				if (org.apache.commons.lang3.StringUtils.equals(template.toString(), str)) {
					this.templateSupportCache.setTemplateString(filePath, str);
				}
			}

			return str;
		} catch (final IOException e) {
			throw new IllegalArgumentException(e);
		} catch (final TemplateException e) {
			throw new IllegalArgumentException(e);
		}
	}

	@Override
	public String processTemplateIntoString(final String filePath, final Object model) {
		return this.processTemplateIntoString(filePath, true, model);
	}
}
